#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QCloseEvent>
#include <QMessageBox>
#include <QPainter>
#include <QSettings>
#include <QVariant>
#include <QMimeData>
#include <QFile>
#include <QFileInfo>
#include <QFileDialog>
#include "NVM.h"
#include "ObjectQueue.hpp"




static uint32_t JoyPadStatusToButtonStatus(GamePadInput::JoyPadStatus& Status);




MainWindow::MainWindow(QWidget* parent):QMainWindow(parent),ui(new Ui::MainWindow){
  ui->setupUi(this);


  StatusLabel=new QLabel("FPS:0");
  ui->statusbar->addPermanentWidget(StatusLabel);
  ui->statusbar->showMessage("窗口打开",2000);


  videoSettingsDialog=nullptr;
  audioSettingsDialog=nullptr;
  inputSettingsDialog=nullptr;
  logDialog=nullptr;


  timerFPS=new QTimer(this);
  timerFPS->setInterval(1000);
  connect(timerFPS,&QTimer::timeout,this,&MainWindow::TimerFPS_Callback);

  timerPad=new QTimer(this);
  timerPad->setInterval(8);
  connect(timerPad,&QTimer::timeout,this,&MainWindow::TimerPad_Callback);

  timerLog=new QTimer(this);
  timerLog->setInterval(16);
  connect(timerLog,&QTimer::timeout,this,&MainWindow::TimerLog_Callback);

  metaKey=QMetaEnum::fromType<Qt::Key>();

  
  ButtonStatus0=0U;
  ButtonStatus1=0U;
  FrameCount=0;
  
  displayMult=1;

  NES_IsRun=false;

  rom=nullptr;
  this->Path=QString();
  
  TVStandards=0;
  VblankNMI_Delay=0;
  MMC3_CountDelay=16;
  SampleRate=H_NES_CPP::SampleRate::SampleRate_384000;
  NumOfSampleBit=32;
  PulseLR_Diff=0;


  audioOutput=new AudioOutput();

  gamePadInput=new GamePadInput((void*)this->winId(),2);
  try{
    gamePadInput->Open();
  }catch(const char* e){
    qDebug()<<e;
  }

  nes_InputMapper=new NES_InputMapper();


  nes=new NES(H_NES_CPP::SampleRate::SampleRate_384000,32,this);
  nes->SetVolume_M(100);



  
  timerFPS->start();
  timerPad->start();
  timerLog->start();
}

MainWindow::~MainWindow(){

  delete nes;
  delete nes_InputMapper;
  delete gamePadInput;
  delete audioOutput;
  delete ui;
}




void MainWindow::LoadSettings(){

  QVariant nullVar=QVariant(QByteArray());
  QByteArray var;

  
  var=NVM::settings->value("mainwindow/state",nullVar).toByteArray();
  if(!var.isEmpty()){
    restoreState(var);
  }
  var=NVM::settings->value("mainwindow/geometry",nullVar).toByteArray();
  if(!var.isEmpty()){
    restoreGeometry(var);
  }

  SetDisplayMult(NVM::settings->value("displaylabel/mult",QVariant((int)1)).toInt());

  nes->SetPalette(VideoSettingsDialog::Palettes(NVM::settings->value("displaysetting/palette",QVariant((int)0)).toInt()));
  
  SetTVStandards(NVM::settings->value("displaysetting/tvstandards",QVariant((int)0)).toInt());
  SetVblankNMI_Delay(NVM::settings->value("displaysetting/vblanknmidelay",QVariant((int)0)).toInt());
  SetMMC3_CountDelay(NVM::settings->value("displaysetting/mmc3countdelay",QVariant((int)16)).toInt());

  SetAudioFormat(
    (H_NES_CPP::SampleRate)NVM::settings->value("audiosetting/samplerate",QVariant((int)H_NES_CPP::SampleRate::SampleRate_384000)).toInt()
    ,NVM::settings->value("audiosetting/numofsamplebit",QVariant((int)32)).toInt());
  SetPulseLR_Diff(NVM::settings->value("audiosetting/pulselrdiff",QVariant((int)0)).toInt());

  var=NVM::settings->value("inputsettings/inputmapper",nullVar).toByteArray();
  if(!var.isEmpty()){
    nes_InputMapper->SetKeyMapper_Array(var);
  }else{
    nes_InputMapper->SetKeyMapper(H_NES_CPP::StandardControllerStatus::Pad1P_A,(int)InputDeviceIndex::Keyboard,(uint32_t)Qt::Key::Key_2);
    nes_InputMapper->SetKeyMapper(H_NES_CPP::StandardControllerStatus::Pad1P_B,(int)InputDeviceIndex::Keyboard,(uint32_t)Qt::Key::Key_1);
    nes_InputMapper->SetKeyMapper(H_NES_CPP::StandardControllerStatus::Pad1P_AutoA,(int)InputDeviceIndex::Keyboard,(uint32_t)Qt::Key::Key_5);
    nes_InputMapper->SetKeyMapper(H_NES_CPP::StandardControllerStatus::Pad1P_AutoB,(int)InputDeviceIndex::Keyboard,(uint32_t)Qt::Key::Key_4);
    nes_InputMapper->SetKeyMapper(H_NES_CPP::StandardControllerStatus::Pad1P_Select,(int)InputDeviceIndex::Keyboard,(uint32_t)Qt::Key::Key_E);
    nes_InputMapper->SetKeyMapper(H_NES_CPP::StandardControllerStatus::Pad1P_Start,(int)InputDeviceIndex::Keyboard,(uint32_t)Qt::Key::Key_R);
    nes_InputMapper->SetKeyMapper(H_NES_CPP::StandardControllerStatus::Pad1P_Up,(int)InputDeviceIndex::Keyboard,(uint32_t)Qt::Key::Key_W);
    nes_InputMapper->SetKeyMapper(H_NES_CPP::StandardControllerStatus::Pad1P_Down,(int)InputDeviceIndex::Keyboard,(uint32_t)Qt::Key::Key_S);
    nes_InputMapper->SetKeyMapper(H_NES_CPP::StandardControllerStatus::Pad1P_Left,(int)InputDeviceIndex::Keyboard,(uint32_t)Qt::Key::Key_A);
    nes_InputMapper->SetKeyMapper(H_NES_CPP::StandardControllerStatus::Pad1P_Right,(int)InputDeviceIndex::Keyboard,(uint32_t)Qt::Key::Key_D);
  }



}

void MainWindow::SetDisplayMult(int Mult){
  if(Mult<displayMult){

    displayMult=Mult;

    ui->NESDisplay->setMinimumSize(256*Mult,240*Mult);
    ui->NESDisplay->setMaximumSize(256*Mult,240*Mult);

  }else if(Mult>displayMult){

    displayMult=Mult;

    ui->NESDisplay->setMaximumSize(256*Mult,240*Mult);
    ui->NESDisplay->setMinimumSize(256*Mult,240*Mult);

  }
  
}

int MainWindow::GetDisplayMult(){
  return displayMult;
}

void MainWindow::SetTVStandards(int TVStandards){
  this->TVStandards=TVStandards;
}

int MainWindow::GetTVStandards(){
  return TVStandards;
}

void MainWindow::SetVblankNMI_Delay(int VblankNMI_Delay){
  this->VblankNMI_Delay=VblankNMI_Delay;

  nes->SetVblankNMI_Delay(VblankNMI_Delay);
}

int MainWindow::GetVblankNMI_Delay(){
  return VblankNMI_Delay;
}

void MainWindow::SetMMC3_CountDelay(int MMC3_CountDelay){
  this->MMC3_CountDelay=MMC3_CountDelay;
  nes->SetMMC3_CountDelay(MMC3_CountDelay);
}

int MainWindow::GetMMC3_CountDelay(){
  return MMC3_CountDelay;
}

void MainWindow::SetSampleRate(H_NES_CPP::SampleRate SampleRate){
  this->SampleRate=SampleRate;
  nes->SetSampleRate(SampleRate);
}

H_NES_CPP::SampleRate MainWindow::GetSampleRate(){
  return SampleRate;
}

void MainWindow::SetNumOfSampleBit(int NumOfSampleBit){
  this->NumOfSampleBit=NumOfSampleBit;
  nes->SetNumOfSampleBit(NumOfSampleBit);
}

int MainWindow::GetNumOfSampleBit(){
  return NumOfSampleBit;
}

void MainWindow::SetPulseLR_Diff(int PulseLR_Diff){
  this->PulseLR_Diff=PulseLR_Diff;
  nes->SetPulseLR_Diff(PulseLR_Diff);
}

int MainWindow::GetPulseLR_Diff(){
  return PulseLR_Diff;
}

void MainWindow::SetAudioFormat(H_NES_CPP::SampleRate SampleRate,int NumOfSampleBit){
  this->SampleRate=SampleRate;
  this->NumOfSampleBit=NumOfSampleBit;

  nes->SetFormat(SampleRate,NumOfSampleBit);
}

void MainWindow::NES_InputPress(InputDeviceIndex Index,uint32_t Button){
  
  if(inputSettingsDialog!=nullptr){
    inputSettingsDialog->PadPressEvent((int)Index,Button);
  }

  nes_InputMapper->InputPress((int)Index,Button);
}

void MainWindow::NES_InputRelease(InputDeviceIndex Index,uint32_t Button){
  
  if(inputSettingsDialog!=nullptr){
    inputSettingsDialog->PadReleaseEvent((int)Index,Button);
  }

  nes_InputMapper->InputRelease((int)Index,Button);
}

void MainWindow::VideoSettingsDialogCloseEvent(){
  videoSettingsDialog=nullptr;
}

void MainWindow::AudioSettingsDialogCloseEvent(){
  audioSettingsDialog=nullptr;
}

void MainWindow::InputSettingsDialogCloseEvent(){
  inputSettingsDialog=nullptr;
}

void MainWindow::LogDialogCloseEvent(){
  logDialog=nullptr;
}




uint32_t MainWindow::GetPadStatus(){
  return nes_InputMapper->GetButtonPressStatus();
}

void MainWindow::DisplayNESFrame(void* Bitmap){

  ui->NESDisplay->InputFrame((uint32_t*)Bitmap);
  
  delete[] (uint32_t*)Bitmap;

  FrameCount++;

}

void MainWindow::AudioDeviceError(QString Error){
  audioOutput->Close();
  QMessageBox::critical(this,"错误",Error);
}




void MainWindow::closeEvent(QCloseEvent* event){

  Q_UNUSED(event);

  if(videoSettingsDialog!=nullptr){
    videoSettingsDialog->close();
  }
  if(audioSettingsDialog!=nullptr){
    audioSettingsDialog->close();
  }
  if(inputSettingsDialog!=nullptr){
    inputSettingsDialog->close();
  }
  if(logDialog!=nullptr){
    logDialog->close();
  }

  NVM::settings->setValue("mainwindow/geometry",QVariant(saveGeometry()));
  NVM::settings->setValue("mainwindow/state",QVariant(saveState()));
  NVM::settings->setValue("displaylabel/mult",QVariant((int)displayMult));

  NVM::settings->setValue("displaysetting/palette",QVariant((int)VideoSettingsDialog::FindPalettesIndex(nes->GetPalette())));
  NVM::settings->setValue("displaysetting/tvstandards",QVariant((int)GetTVStandards()));
  NVM::settings->setValue("displaysetting/vblanknmidelay",QVariant((int)GetVblankNMI_Delay()));
  NVM::settings->setValue("displaysetting/mmc3countdelay",QVariant((int)GetMMC3_CountDelay()));

  NVM::settings->setValue("audiosetting/samplerate",QVariant((int)GetSampleRate()));
  NVM::settings->setValue("audiosetting/numofsamplebit",QVariant((int)GetNumOfSampleBit()));
  NVM::settings->setValue("audiosetting/pulselrdiff",QVariant((int)GetPulseLR_Diff()));

  NVM::settings->setValue("inputsettings/inputmapper",QVariant(nes_InputMapper->GetKeyMapper_Array()));


  NVM::DeInit();

  if(NES_IsRun){
    nes->Stop();
  }
}

void MainWindow::dragEnterEvent(QDragEnterEvent* event){
  if(event->mimeData()->urls().first().isLocalFile()){
    event->acceptProposedAction();
  }
}

void MainWindow::dropEvent(QDropEvent* event){
  QString name = event->mimeData()->urls().first().toLocalFile();

  QFileInfo info(name);

  QString suffix=info.suffix();

  if(0==QString::compare(suffix,QString("pgs"),Qt::CaseInsensitive)){
    LoadProgress(name);
  }else{
    if(NES_IsRun){
      Stop();
    }
    Start(name);
    activateWindow();
  }

}

void MainWindow::keyPressEvent(QKeyEvent* event){
  NES_InputPress(InputDeviceIndex::Keyboard,(uint32_t)event->key());
}

void MainWindow::keyReleaseEvent(QKeyEvent* event){
  NES_InputRelease(InputDeviceIndex::Keyboard,(uint32_t)event->key());
}




void MainWindow::Start(QString& Path){
  H_NES_CPP::TVStandards tvStandards;

  if(NES_IsRun){
    return;
  }

  QFile file(Path);

  if(!file.open(QIODeviceBase::ReadOnly)){
    return;
  }

  qint64 fileSize;

  fileSize=file.size();

  if(fileSize>1024*1024*10){
    file.close();
    QMessageBox::critical(this,"错误","过大的ROM");
    return;
  }

  rom=new unsigned char[fileSize];

  
  switch(TVStandards){
    case 1:
      tvStandards=H_NES_CPP::TVStandards::PAL;
      break;
    case 2:
      tvStandards=H_NES_CPP::TVStandards::Dendy;
      break;
    default:
      tvStandards=H_NES_CPP::TVStandards::NTSC;
      break;
  }

  try{
    if(fileSize!=file.read((char*)rom,fileSize)){
      throw "读取文件错误:长度错误";
    }
    nes->SetTelevisionStandards(tvStandards);
    nes->Start(rom);
    NES_IsRun=true;

    UI_IsRun(NES_IsRun);

    this->Path=Path;

    ui->NESDisplay->SetIsDisplay(true);
    ui->statusbar->showMessage("H_NES启动...",3000);

  }catch(const char* e){
    delete[] rom;
    rom=nullptr;
    QMessageBox::critical(this,"错误",e);
  }

  file.close();
}

void MainWindow::Stop(){

  if(NES_IsRun){
    NES_IsRun=false;
    
    nes->Stop();

    delete[] rom;
    rom=nullptr;

    UI_IsRun(NES_IsRun);

    this->Path=QString();

    ui->NESDisplay->SetIsDisplay(false);
    ui->statusbar->showMessage("H_NES停止",3000);

  }

}

QString MainWindow::ProgressFileName(QString Tag){

  QFileInfo info(Path);

  return info.absolutePath()+"/H_NES_Progress/"+info.completeBaseName()+Tag+".pgs";
}

void MainWindow::SaveProgress(QString Path){

  if(!NES_IsRun){
    QMessageBox::critical(this,"错误","NES未运行");
    return;
  }

  QFileInfo info(Path);
  QString DirName=info.absolutePath();
  QDir dir(DirName);

  if(!dir.exists()){
    if(!dir.mkpath(DirName)){
      QMessageBox::critical(this,"错误","未能创建文件");
      return;
    }
  }

  if(!Path.isEmpty()){
    char* Progress=nullptr;

    QFile file(Path);
    
    try{
      qint64 ProgressSize=nes->GetProgress((unsigned char**)&Progress);

      if(!file.open(QIODeviceBase::WriteOnly|QIODeviceBase::Truncate)){
        qDebug()<<Path<<Qt::endl;
        throw "文件无法创建";
      }

      if(ProgressSize!=file.write(Progress,ProgressSize)){
        throw "无法完整写入文件";
      }

      ui->statusbar->showMessage("存档成功!",3000);

    }catch(const char* e){
      QMessageBox::critical(this,"错误",QString("保存文件失败, 原因:")+e);
    }
    if(file.isOpen()){
      file.close();
    }
    if(Progress!=nullptr){
      delete[] (unsigned char*)Progress;
    }
  }
}

void MainWindow::LoadProgress(QString Path){

  if(!NES_IsRun){
    QMessageBox::critical(this,"错误","NES未运行");
    return;
  }

  if(!Path.isEmpty()){
    char* Progress=nullptr;
    
    QFile file(Path);
    
    try{
      qint64 ProgressSize=nes->GetProgressSize();

      if(!file.open(QIODeviceBase::ReadOnly)){
        throw "文件无法打开";
      }

      if(file.size()!=ProgressSize){
        throw "存档文件错误, 不正确的长度";
      }

      Progress=(char*)new unsigned char[ProgressSize];

      if(ProgressSize!=file.read(Progress,ProgressSize)){
        throw "无法完整读取文件";
      }

      nes->LoadProgress((unsigned char*)Progress);

      ui->statusbar->showMessage("加载存档成功!",3000);

    }catch(const char* e){
      QMessageBox::critical(this,"错误",QString("加载存档失败, 原因:")+e);
    }
    if(file.isOpen()){
      file.close();
    }
    if(Progress!=nullptr){
      delete[] (unsigned char*)Progress;
    }
  }
}

void MainWindow::UI_IsRun(bool IsRun){
  ui->actionClose->setEnabled(IsRun);
  ui->actionReset->setEnabled(IsRun);
  ui->actionPower->setEnabled(IsRun);
  ui->actionQuickSave->setEnabled(IsRun);
  ui->actionQuickLoad->setEnabled(IsRun);
  ui->actionSaveSlot0->setEnabled(IsRun);
  ui->actionSaveSlot1->setEnabled(IsRun);
  ui->actionSaveSlot2->setEnabled(IsRun);
  ui->actionSaveSlot3->setEnabled(IsRun);
  ui->actionLoadSlot0->setEnabled(IsRun);
  ui->actionLoadSlot1->setEnabled(IsRun);
  ui->actionLoadSlot2->setEnabled(IsRun);
  ui->actionLoadSlot3->setEnabled(IsRun);
  ui->actionSave->setEnabled(IsRun);
  ui->actionLoad->setEnabled(IsRun);
}

void MainWindow::PadPressEvent(int Index,uint32_t Button){
  if(Index==0){
    NES_InputPress(InputDeviceIndex::GamePad0,Button);
  }else if(Index==1){
    NES_InputPress(InputDeviceIndex::GamePad1,Button);
  }
}

void MainWindow::PadReleaseEvent(int Index,uint32_t Button){
  if(Index==0){
    NES_InputRelease(InputDeviceIndex::GamePad0,Button);
  }else if(Index==1){
    NES_InputRelease(InputDeviceIndex::GamePad1,Button);
  }
}




void MainWindow::TimerFPS_Callback(){
  StatusLabel->setText(QString("FPS:")+QString::number(FrameCount));
  FrameCount=0;
}

void MainWindow::TimerPad_Callback(){
  GamePadInput::JoyPadStatus status0;
  GamePadInput::JoyPadStatus status1;
  uint32_t ButtonStatus0;
  uint32_t ButtonStatus1;
  uint32_t sButtonStatus0;
  uint32_t sButtonStatus1;
  
  uint32_t PressMask;
  uint32_t ReleaseMask;

  uint32_t Button;

  gamePadInput->GetPadStatus(0,&status0);
  gamePadInput->GetPadStatus(1,&status1);

  ButtonStatus0=JoyPadStatusToButtonStatus(status0);
  ButtonStatus1=JoyPadStatusToButtonStatus(status1);

  sButtonStatus0=this->ButtonStatus0^ButtonStatus0;
  sButtonStatus1=this->ButtonStatus1^ButtonStatus1;

  this->ButtonStatus0=ButtonStatus0;
  this->ButtonStatus1=ButtonStatus1;

  PressMask=ButtonStatus0&sButtonStatus0;
  ReleaseMask=(~ButtonStatus0)&sButtonStatus0;

  Button=0x80000000U;
  while(Button!=0U){
    if((PressMask&Button)!=0U){
      PadPressEvent(0,Button);
    }else if((ReleaseMask&Button)!=0U){
      PadReleaseEvent(0,Button);
    }
    Button>>=1;
  }
  

  PressMask=ButtonStatus1&sButtonStatus1;
  ReleaseMask=(~ButtonStatus1)&sButtonStatus1;

  Button=0x80000000U;
  while(Button!=0U){
    if((PressMask&Button)!=0U){
      PadPressEvent(1,Button);
    }else if((ReleaseMask&Button)!=0U){
      PadReleaseEvent(1,Button);
    }
    Button>>=1;
  }


}

void MainWindow::TimerLog_Callback(){
  extern ObjectQueue<QByteArray>* H_PrintfArray;

  QByteArray* arr;

  if(logDialog!=nullptr){
    while(nullptr!=(arr=H_PrintfArray->TryRead())){
      logDialog->AddLog(QString::fromUtf8(arr[0]));
      delete arr;
    }
  }else{
    while(nullptr!=(arr=H_PrintfArray->TryRead())){
      delete arr;
    }
  }

}




void MainWindow::on_actionInfo_triggered(){
  QMessageBox::information(this,"信息",
    "Designer by 0x9DEFA478\r\n"
    "  本程序是在Qt平台下实现的window程序, 使用H_NES作为NES模拟器");
}

void MainWindow::on_actionOpenGLVersion_triggered(){
   QMessageBox::information(this,"信息",
    "OpenGL版本:\r\n  "+ui->NESDisplay->GetOpenGLVersion());
}

void MainWindow::on_actionOpen_triggered(){

  QString path=QFileDialog::getOpenFileName(this,"选择ROM文件",QString(),"nes文件(*.nes);;所有文件(*.*)");

  if(path.isEmpty()){
    return;
  }

  if(NES_IsRun){
    Stop();
  }
  Start(path);

}

void MainWindow::on_actionClose_triggered(){
  if(NES_IsRun){
    Stop();
  }
}

void MainWindow::on_actionReset_triggered(){
  if(NES_IsRun){
    nes->Reset();
    ui->statusbar->showMessage("H_NES Reset",3000);
  }
}

void MainWindow::on_actionPower_triggered(){
  H_NES_CPP::TVStandards tvStandards;

  if(NES_IsRun){
    nes->Stop();
  
    try{

      switch(TVStandards){
        case 1:
          tvStandards=H_NES_CPP::TVStandards::PAL;
          break;
        case 2:
          tvStandards=H_NES_CPP::TVStandards::Dendy;
          break;
        default:
          tvStandards=H_NES_CPP::TVStandards::NTSC;
          break;
      }

      nes->SetTelevisionStandards(tvStandards);
      nes->Start(rom);

      ui->statusbar->showMessage("H_NES重启",3000);
    }catch(const char* e){
      delete[] rom;
      rom=nullptr;
      NES_IsRun=false;
      UI_IsRun(NES_IsRun);
      QMessageBox::critical(this,"错误",e);
    }
  }

}


void MainWindow::on_actionVideoSettings_triggered(){
  VideoSettingsDialog* form;

  if(videoSettingsDialog!=nullptr){
    videoSettingsDialog->activateWindow();
    return;
  }

  form=new VideoSettingsDialog(this,this);
  form->setWindowModality(Qt::WindowModality::NonModal);
  form->setAttribute(Qt::WidgetAttribute::WA_DeleteOnClose);
  form->show();

  videoSettingsDialog=form;
}

void MainWindow::on_actionAudioSettings_triggered(){
  AudioSettingsDialog* form;

  if(audioSettingsDialog!=nullptr){
    audioSettingsDialog->activateWindow();
    return;
  }

  form=new AudioSettingsDialog(this,this);
  form->setWindowModality(Qt::WindowModality::NonModal);
  form->setAttribute(Qt::WidgetAttribute::WA_DeleteOnClose);
  form->show();

  audioSettingsDialog=form;
}

void MainWindow::on_actionInputSettings_triggered(){
  InputSettingsDialog* form;

  if(inputSettingsDialog!=nullptr){
    inputSettingsDialog->activateWindow();
    return;
  }

  form=new InputSettingsDialog(this,this);
  form->setWindowModality(Qt::WindowModality::NonModal);
  form->setAttribute(Qt::WidgetAttribute::WA_DeleteOnClose);
  form->show();

  inputSettingsDialog=form;
}

void MainWindow::on_actionH_NES_Output_triggered(){
  LogDialog* form;

  if(logDialog!=nullptr){
    logDialog->activateWindow();
    return;
  }

  form=new LogDialog(this,this);
  form->setWindowModality(Qt::WindowModality::NonModal);
  form->setAttribute(Qt::WidgetAttribute::WA_DeleteOnClose);
  form->show();

  logDialog=form;
}





#define ProgressQuickSave_Tag "-QuickSave"

#define ProgressSaveSlot_Tag(_in_Index) "-SaveSlot"#_in_Index

void MainWindow::on_actionQuickSave_triggered(){
  SaveProgress(ProgressFileName(QString(ProgressQuickSave_Tag)));
}

void MainWindow::on_actionQuickLoad_triggered(){
  LoadProgress(ProgressFileName(QString(ProgressQuickSave_Tag)));
}

void MainWindow::on_actionSaveSlot0_triggered(){
  SaveProgress(ProgressFileName(QString(ProgressSaveSlot_Tag(0))));
}

void MainWindow::on_actionSaveSlot1_triggered(){
  SaveProgress(ProgressFileName(QString(ProgressSaveSlot_Tag(1))));
}

void MainWindow::on_actionSaveSlot2_triggered(){
  SaveProgress(ProgressFileName(QString(ProgressSaveSlot_Tag(2))));
}

void MainWindow::on_actionSaveSlot3_triggered(){
  SaveProgress(ProgressFileName(QString(ProgressSaveSlot_Tag(3))));
}

void MainWindow::on_actionLoadSlot0_triggered(){
  LoadProgress(ProgressFileName(QString(ProgressSaveSlot_Tag(0))));
}

void MainWindow::on_actionLoadSlot1_triggered(){
  LoadProgress(ProgressFileName(QString(ProgressSaveSlot_Tag(1))));
}

void MainWindow::on_actionLoadSlot2_triggered(){
  LoadProgress(ProgressFileName(QString(ProgressSaveSlot_Tag(2))));
}

void MainWindow::on_actionLoadSlot3_triggered(){
  LoadProgress(ProgressFileName(QString(ProgressSaveSlot_Tag(3))));
}

void MainWindow::on_actionSave_triggered(){

  QString path=QFileDialog::getSaveFileName(this,"选择保存位置",QString(),"pgs文件(*.pgs)");

  if(path.isEmpty()){
    return;
  }

  SaveProgress(path);
}

void MainWindow::on_actionLoad_triggered(){

  QString path=QFileDialog::getOpenFileName(this,"选择存档文件",QString(),"pgs文件(*.pgs)");

  if(path.isEmpty()){
    return;
  }

  LoadProgress(path);
}




QMetaEnum MainWindow::metaKey=QMetaEnum::fromType<Qt::Key>();




static uint32_t JoyPadStatusToButtonStatus(GamePadInput::JoyPadStatus& Status){
  uint32_t r;
  int val;

  r=0;

  val=Status.X;
  if(val>0){
    r|=0x1U<<20;
  }else if(val<0){
    r|=0x1U<<21;
  }
  val=Status.Y;
  if(val>0){
    r|=0x1U<<22;
  }else if(val<0){
    r|=0x1U<<23;
  }
  val=Status.Z;
  if(val>0){
    r|=0x1U<<24;
  }else if(val<0){
    r|=0x1U<<25;
  }
  val=Status.RX;
  if(val>0){
    r|=0x1U<<26;
  }else if(val<0){
    r|=0x1U<<27;
  }
  val=Status.RY;
  if(val>0){
    r|=0x1U<<28;
  }else if(val<0){
    r|=0x1U<<29;
  }
  val=Status.RZ;
  if(val>0){
    r|=0x1U<<30;
  }else if(val<0){
    r|=0x1U<<31;
  }

  r|=Status.Buttons&0x000FFFFFU;

  return r;
}

static QString ButtonStatusToString(uint32_t Button){
  int i;

  i=31;

  while(i>=0){
    if((Button&(0x1U<<i))!=0U){
      break;
    }
    i--;
  }

  if(i<0){
    return QString("Unknow");
  }

  const char* ButtonString[]={
    "Button_00",
    "Button_01",
    "Button_02",
    "Button_03",
    "Button_04",
    "Button_05",
    "Button_06",
    "Button_07",
    "Button_08",
    "Button_09",
    "Button_10",
    "Button_11",
    "Button_12",
    "Button_13",
    "Button_14",
    "Button_15",
    "Button_16",
    "Button_17",
    "Button_18",
    "Button_19",
    "X+",
    "X-",
    "Y+",
    "Y-",
    "Z+",
    "Z-",
    "RX+",
    "RX-",
    "RY+",
    "RY-",
    "RZ+",
    "RZ-",
  };

  return QString(ButtonString[i]);
}

QString MainWindow::ButtonToString(InputDeviceIndex Index,uint32_t Button){
  
  switch(Index){
    case InputDeviceIndex::Keyboard:
      return QString(metaKey.valueToKey((int)Button));
    case InputDeviceIndex::GamePad0:
      return QString("GamePad0")+ButtonStatusToString(Button);
    case InputDeviceIndex::GamePad1:
      return QString("GamePad1")+ButtonStatusToString(Button);
    default:
      break;
  }

  return QString("Unknow");
}



